package com.anche.cywebnew.Utils.netsdk.product;

import com.anche.cywebnew.Utils.Thread.LxThreadPoolUtil;
import com.anche.cywebnew.Utils.netsdk.HCNetSDK;
import com.anche.cywebnew.Utils.netsdk.callback.DownloadCompleted;
import com.anche.cywebnew.Utils.netsdk.pojo.DownloadPara;
import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;

import java.io.File;
import java.io.FileInputStream;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

import static com.anche.cywebnew.Utils.netsdk.HCNetSDK.NETSDK_INSTANCE;

public class HikRecorder implements Recorder {

    public static HCNetSDK netsdk;

    public HikRecorder() {
        netsdk = NETSDK_INSTANCE;
    }

    @Override
    public Map<String, Object> doInit() {
        Map<String, Object> result = new HashMap<>();
        boolean bInit;
        bInit = netsdk.NET_DVR_Init();
        if (!bInit) {
            result.put("code", "0");
        } else {
            result.put("code", "1");
        }
        return result;
    }

    @Override
    public Map<String, Object> doLogin(String ip, int port, String username, String password) {
        Map<String, Object> result = new HashMap<>();
        HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
        String hip =ip;
        short hport = (short) port;
        String hyh = username;
        String hmm = password;
        NativeLong lUserID = netsdk.NET_DVR_Login_V30(hip, hport, hyh, hmm, m_strDeviceInfo);
        if (lUserID.longValue() != -1) {
            result.put("code", "1");
            result.put("loginHandle", lUserID);
        } else {
            String msg = String.format("登陆设备IP[%s] Port[%d]失败. %s", hip, hport, netsdk.NET_DVR_GetLastError());
            result.put("code", "0");
            result.put("msg", msg);
        }
        return result;
    }

    @Override
    public Map<String, Object> doDownload(Object m_hDownLoadHandle1, List<DownloadPara> downloadParas) {
        NativeLong m_hLoginHandle = (NativeLong) m_hDownLoadHandle1;
        Map<String, Object> result = new HashMap<>();
        ThreadPoolExecutor threadPool = LxThreadPoolUtil.getThreadPool();  // 获取公共线程池
        try {
            int size = downloadParas.size();
            int i = 0;
            AtomicInteger atomicInteger = new AtomicInteger();
            CountDownLatch latch = new CountDownLatch(downloadParas.size());
            for (DownloadPara downloadPara : downloadParas) {
                // 多线程执行
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        DownloadCompleted completed = downloadPara.getCompleted();
                        try {
                            System.out.println("共" + size + "条，当前下载第" + atomicInteger.getAndAdd(1) + "条");
                            // 下载句柄
                            NativeLong m_hDownLoadHandle;
                            // 按时间下载回调
                            //DownLoadPosCallBackByTime m_DownLoadPosByTime = new DownLoadPosCallBackByTime(); // 录像下载进度
                            HCNetSDK.NET_DVR_TIME struStartTime = convertDate(downloadPara.getStartDate());
                            HCNetSDK.NET_DVR_TIME struStopTime = convertDate(downloadPara.getEndDate());
                            m_hDownLoadHandle = netsdk.NET_DVR_GetFileByTime(m_hLoginHandle, new NativeLong(downloadPara.getChannel()), struStartTime, struStopTime, downloadPara.getFilePath());
                            if (m_hDownLoadHandle.intValue() >= 0) {
                                netsdk.NET_DVR_PlayBackControl(m_hDownLoadHandle, HCNetSDK.NET_DVR_PLAYSTART, 0, null);
                                IntByReference nPos = new IntByReference(0);
                                do {
//                                    try {
                                        netsdk.NET_DVR_PlayBackControl(m_hDownLoadHandle, HCNetSDK.NET_DVR_PLAYGETPOS, 0, nPos);
                                        Thread.sleep(3000);
//                                    } catch (Exception e) {
//                                        e.printStackTrace();
//                                        completed.failed(downloadPara.getId(), "下载录像时异常：" + e.getMessage());
//                                        break;
//                                    }
                                } while (nPos.getValue() < 100);
                                if (nPos.getValue() == 100) {
                                    netsdk.NET_DVR_StopGetFile(m_hDownLoadHandle);
                                    String fileSize = getFileSize(downloadPara.getFilePath());
                                    if ("0KB".equals(fileSize)) {
                                        completed.failed(downloadPara.getId(), "下载大小为0KB");
                                    } else {
                                        completed.success(downloadPara.getId(), downloadPara.getFilePath());
                                    }
                                } else if (nPos.getValue() > 100) {
                                    String msg = String.format("设备下载录像时失败. %s", netsdk.NET_DVR_GetLastError());
                                    netsdk.NET_DVR_StopGetFile(m_hDownLoadHandle);
                                    completed.failed(downloadPara.getId(), msg);
                                }
                            } else {
                                String msg = String.format("设备开始下载失败. %s", netsdk.NET_DVR_GetLastError());
                                netsdk.NET_DVR_StopGetFile(m_hDownLoadHandle);
                                completed.failed(downloadPara.getId(), msg);
                            }
                        }catch (Exception e){
                            e.printStackTrace();
                            completed.failed(downloadPara.getId(), "下载录像时异常：" + e.getMessage());
                        }finally {
                            latch.countDown();
                        }
                    }
                });
            }
            latch.await();  // 等待所有下载线程下载完毕，推出登录
            boolean logout = netsdk.NET_DVR_Logout(m_hLoginHandle);
            if (logout) {
                System.out.println("用户登出成功");
            } else {
                String msg = String.format("用户登出失败. %s", netsdk.NET_DVR_GetLastError());
                System.err.println(msg);
            }
            result.put("code", "1");
        } catch (Exception e) {
            result.put("code", "1");
            result.put("msg", e.getMessage());
        }
        return result;
    }

    private HCNetSDK.NET_DVR_TIME convertDate(Date inputDate) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(inputDate);                    //放入Date类型数据

        int year = ca.get(Calendar.YEAR);                    //获取年份
        int month = ca.get(Calendar.MONTH) + 1;                    //获取月份
        int day = ca.get(Calendar.DATE);                    //获取日

        int hour = ca.get(Calendar.HOUR_OF_DAY);                //时（24小时制）
        int minute = ca.get(Calendar.MINUTE);                    //分
        int second = ca.get(Calendar.SECOND);                    //秒
        HCNetSDK.NET_DVR_TIME output = new HCNetSDK.NET_DVR_TIME();
        output.dwYear = year;
        output.dwMonth = month;
        output.dwDay = day;
        output.dwHour = hour;
        output.dwMinute = minute;
        output.dwSecond = second;
        return output;
    }

    /**
     * 传入文件路径，可以得到文件的大小信息
     *
     * @param path 文件路径
     * @return
     */
    public static String getFileSize(String path) {
        String resourceSizeMb = null;
        try {
            // 指定路径即可
            File f = new File(path);

            FileInputStream fis = new FileInputStream(f);

            DecimalFormat df = new DecimalFormat("#.##");

            // double resourceSize = (double)((double) fis.available() / 1024);
            // ELog.e(TAG, "resourceSize:" + resourceSize);

            if ((double) ((double) fis.available() / 1024) > 1000) {
                resourceSizeMb = df.format((double) ((double) fis.available() / 1024 / 1024)) + "MB";
            } else {
                resourceSizeMb = df.format((double) ((double) fis.available() / 1024)) + "KB";
            }

        } catch (Exception e) {
            e.printStackTrace();
            resourceSizeMb = null;
        }
        return resourceSizeMb;
    }
}
